﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MacomberMapSystem.Common.Serialization;
using System.Xml;
using MacomberMapSystem.Common.Internals;
using System.Data.Common;

namespace MacomberMapSystem.Common.Database
{
    /// <summary>
    /// This class provides information on a database entry
    /// </summary>
    public class MM_Database_Entry : MM_Serializable, IComparable<MM_Database_Entry>, IEquatable<MM_Database_Entry>
    {
        #region Variable declarations
        /// <summary>The name of the database connection</summary>
        [MM_Serializable_Target(MM_Serializable_Target.enumTargetType.FieldValue)]
        public String Name;

        /// <summary>The data source for our connectivity</summary>
        [MM_Serializable_Target(MM_Serializable_Target.enumTargetType.FieldValue)]
        public String DataSource;

        /// <summary>The user name to connect to our database</summary>
        [MM_Serializable_Target(MM_Serializable_Target.enumTargetType.FieldValue)]
        public String UserName;

        /// <summary>The encrypted password for database connectivity</summary>
        [MM_Serializable_Target(MM_Serializable_Target.enumTargetType.FieldValue)]
        public String EncryptedPassword;

        /// <summary>The collection of database types</summary>
        public enum enumDatabaseType
        {
            /// <summary>An unknown database type</summary>
            Unknown,
            /// <summary>An Oracle database type</summary>
            Oracle,
            /// <summary>A SQLite database type</summary>
            SQLite
        }

        /// <summary>The database type</summary>
        [MM_Serializable_Target(MM_Serializable_Target.enumTargetType.FieldValue)]
        public enumDatabaseType DatabaseType;

        /// <summary>Whether the database should be our default</summary>
        [MM_Serializable_Target(MM_Serializable_Target.enumTargetType.FieldValue)]
        public bool DefaultDatabase = false;

        /// <summary>The decrypted password</summary>
        public String Password
        {
            get { return MM_System_Interface.Decrypt(EncryptedPassword); }
            set { EncryptedPassword = MM_System_Interface.Encrypt(value); }
        }

        #endregion


        #region Initialization
        /// <summary>
        /// Initialize a new database entry
        /// </summary>
        /// <param name="xElem"></param>
        /// <param name="Repository"></param>
        public MM_Database_Entry(XmlElement xElem, MM_Repository Repository)
            : base(xElem, Repository)
        {
            if (xElem.HasAttribute("Type"))
                DatabaseType = MM_Serializable<enumDatabaseType>.ConvertObject(xElem.Attributes["Type"].Value, Repository);
            if (xElem.HasAttribute("Default"))
                DefaultDatabase = XmlConvert.ToBoolean(xElem.Attributes["Default"].Value);
        }

        /// <summary>
        /// Intialize a new database entry
        /// </summary>
        /// <param name="dRd"></param>
        /// <param name="Repository"></param>
        public MM_Database_Entry(DbDataReader dRd, MM_Repository Repository)
            : base(dRd, null, Repository)
        { }

        /// <summary>
        /// Create an outgoing connection
        /// </summary>
        /// <returns></returns>
        public DbConnection CreateConnection()
        {
            if (DatabaseType == enumDatabaseType.Oracle)
#if DotNetOracle
                return new System.Data.OracleClient.OracleConnection(String.Format("User ID={0}; Password={1}; Data Source={2};", UserName, Password, DataSource));
#else
                return new Oracle.DataAccess.Client.OracleConnection(String.Format("User ID={0}; Password={1}; Data Source={2};", UserName, Password, DataSource));
#endif
            else if (DatabaseType == enumDatabaseType.SQLite)
                return new System.Data.SQLite.SQLiteConnection("Data Source=" + DataSource);
            else
                throw new InvalidOperationException("Unknown database type");
        }
        #endregion

        /// <summary>
        /// Report an easy-to-read string for our entry
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            return Name + " (" + DataSource + (DefaultDatabase ? " - DEFAULT)" : ")");
        }

        /// <summary>
        /// Compare two database entries
        /// </summary>
        /// <param name="other"></param>
        /// <returns></returns>
        public int CompareTo(MM_Database_Entry other)
        {
            return Name.CompareTo(other.Name);   
        }

        /// <summary>
        /// Determine whether two entries are equal
        /// </summary>
        /// <param name="other"></param>
        /// <returns></returns>
        public bool Equals(MM_Database_Entry other)
        {
            return String.Equals(Name, other.Name, StringComparison.CurrentCultureIgnoreCase);
        }

        /// <summary>
        /// Determine whether two entries are equal
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <returns></returns>
        public static bool operator ==(MM_Database_Entry x, MM_Database_Entry y)
        {
            return String.Equals(x.Name, y.Name, StringComparison.CurrentCultureIgnoreCase);
        }

        /// <summary>
        /// Determine whether two entries are not equal
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <returns></returns>
        public static bool operator !=(MM_Database_Entry x, MM_Database_Entry y)
        {
            return !String.Equals(x.Name, y.Name, StringComparison.CurrentCultureIgnoreCase);
        }

        /// <summary>
        /// Report a hash code for our db entry
        /// </summary>
        /// <returns></returns>
        public override int GetHashCode()
        {
            return Name.GetHashCode();
        }

        /// <summary>
        /// Determine whether two entries are equal
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public override bool Equals(object obj)
        {
            if (obj is MM_Database_Entry)
                return String.Equals(Name, ((MM_Database_Entry)obj).Name, StringComparison.CurrentCultureIgnoreCase);
            else
                return false;
        }

        /// <summary>
        /// List entries out
        /// </summary>
        /// <param name="Entries"></param>
        /// <param name="ShowTypes">Whether to show the db connection types</param>
        /// <returns></returns>
        public static String ListEntries(IEnumerable<MM_Database_Entry> Entries, bool ShowTypes)
        {
            StringBuilder sB = new StringBuilder();
            sB.AppendLine();
            foreach (MM_Database_Entry Entry in Entries)
                sB.AppendLine("\t" + Entry.Name + (ShowTypes ? " (" + Entry.DatabaseType.ToString() + ")":""));
            return sB.ToString();
        }
    }
}
